#pragma once

#include <G3D/Vector3.h>
#include <G3D/Matrix3.h>

#include <map>
#include <set>

#include "vmap/model_instance.h"
#include "vmap/model.h"
#if 0
#include "ModelInstance.h"
#include "WorldModel.h"
#endif

namespace vmap
{
    /**
     * @brief This Class is used to convert raw vector data into balanced BSP-Trees.
     *
     */
    class ModelPosition
    {
    private:
        G3D::Matrix3 iRotation; /**< TODO */
    public:
        G3D::Vector3 iPos; /**< TODO */
        G3D::Vector3 iDir; /**< TODO */
        float iScale; /**< TODO */
        /**
         * @brief
         *
         */
        void init()
        {
            iRotation = G3D::Matrix3::fromEulerAnglesZYX(G3D::pi() * iDir.y / 180.f, G3D::pi() * iDir.x / 180.f, G3D::pi() * iDir.z / 180.f);
        }
        /**
         * @brief
         *
         * @param pIn
         * @return G3D::Vector3
         */
        G3D::Vector3 transform(const G3D::Vector3& pIn) const;
        /**
         * @brief
         *
         * @param pBasePos
         */
        void moveToBasePos(const G3D::Vector3& pBasePos) { iPos -= pBasePos; }
    };

    /**
     * @brief
     *
     */
    typedef std::map<unsigned int, ModelSpawn> UniqueEntryMap;
    /**
     * @brief
     *
     */
    typedef std::multimap<unsigned int, unsigned int> TileMap;

    /**
     * @brief
     *
     */
    struct MapSpawns
    {
        UniqueEntryMap UniqueEntries; /**< TODO */
        TileMap TileEntries; /**< TODO */
    };

    /**
     * @brief
     *
     */
    typedef std::map<unsigned int, MapSpawns*> MapData;
    //===============================================

    /**
     * @brief
     *
     */
    struct GroupModel_Raw
    {
        unsigned int mogpflags; /**< TODO */
        unsigned int GroupWMOID; /**< TODO */

        G3D::AABox bounds; /**< TODO */
        unsigned int liquidflags; /**< TODO */
        std::vector<MeshTriangle> triangles; /**< TODO */
        std::vector<G3D::Vector3> vertexArray; /**< TODO */
        class WmoLiquid* liquid; /**< TODO */

        /**
         * @brief
         *
         */
        GroupModel_Raw() : liquid(0) {}
        /**
         * @brief
         *
         */
        ~GroupModel_Raw();

        /**
         * @brief
         *
         * @param f
         * @return bool
         */
        bool Read(FILE* f);
    };

    /**
     * @brief
     *
     */
    struct WorldModel_Raw
    {
        unsigned int RootWMOID; /**< TODO */
        std::vector<GroupModel_Raw> groupsArray; /**< TODO */

        /**
         * @brief
         *
         * @param path
         * @return bool
         */
        bool Read(const char* path, const char* RAW_VMAP_MAGIC);
    };

    /**
     * @brief
     *
     */
    class TileAssembler
    {
    private:
        std::string iDestDir; /**< TODO */
        std::string iSrcDir; /**< TODO */
        /**
         * @brief
         *
         * @param pName
         * @return bool
         */
        bool (*iFilterMethod)(char* pName);
        G3D::Table<std::string, unsigned int > iUniqueNameIds; /**< TODO */
        unsigned int iCurrentUniqueNameId; /**< TODO */
        MapData mapData; /**< TODO */
        std::set<std::string> spawnedModelFiles; /**< TODO */

    public:
        /**
         * @brief
         *
         * @param pSrcDirName
         * @param pDestDirName
         */
        TileAssembler(const std::string& pSrcDirName, const std::string& pDestDirName);
        /**
         * @brief
         *
         */
        virtual ~TileAssembler();

        /**
         * @brief
         *
         * @return bool
         */
        bool convertWorld2(const char* RAW_VMAP_MAGIC);
        /**
         * @brief
         *
         * @return bool
         */
        bool readMapSpawns();
        /**
         * @brief
         *
         * @param spawn
         * @return bool
         */
        bool calculateTransformedBound(ModelSpawn& spawn, const char* RAW_VMAP_MAGIC);

        /**
         * @brief
         *
         */
        void exportGameobjectModels(const char* RAW_VMAP_MAGIC);
        /**
         * @brief
         *
         * @param pModelFilename
         * @return bool
         */
        bool convertRawFile(const std::string& pModelFilename, const char* RAW_VMAP_MAGIC);
    };
}

